package com.iqiyi.pps.epg.core.rpc.stream;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.iqiyi.kiwi.utils.DateHelper;
import com.iqiyi.pps.epg.api.model.web.query.TFilter;
import com.iqiyi.pps.epg.api.model.web.query.TPage;
import com.iqiyi.pps.epg.api.model.web.stream.*;
import com.iqiyi.pps.epg.api.server.web.stream.ChannelStreamWebService;
import com.iqiyi.pps.epg.core.model.channel.ChannelBase;
import com.iqiyi.pps.epg.core.model.channel.ChannelConfig;
import com.iqiyi.pps.epg.core.model.encode.EncodeServer;
import com.iqiyi.pps.epg.core.model.log.InterfaceLog;
import com.iqiyi.pps.epg.core.model.rtmp.RtmpServer;
import com.iqiyi.pps.epg.core.model.rtmp.RtmpServerStat;
import com.iqiyi.pps.epg.core.model.stream.LiveChannelStream;
import com.iqiyi.pps.epg.core.model.stream.LiveStream;
import com.iqiyi.pps.epg.core.rpc.qipu.impl.QipuManager;
import com.iqiyi.pps.epg.core.service.channel.ChannelService;
import com.iqiyi.pps.epg.core.service.channel.ChannelServiceImpl;
import com.iqiyi.pps.epg.core.service.encode.EncodeService;
import com.iqiyi.pps.epg.core.service.encode.EncodeServiceImpl;
import com.iqiyi.pps.epg.core.service.log.InterfaceLogService;
import com.iqiyi.pps.epg.core.service.program.ISnapAsyncService;
import com.iqiyi.pps.epg.core.service.rtmp.RtmpService;
import com.iqiyi.pps.epg.core.service.rtmp.RtmpServiceImpl;
import com.iqiyi.pps.epg.core.service.stream.LiveChannelStreamService;
import com.iqiyi.pps.epg.core.service.stream.LiveChannelStreamServiceImpl;
import com.iqiyi.pps.epg.core.service.stream.LiveStreamService;
import com.iqiyi.pps.epg.core.service.stream.LiveStreamServiceImpl;
import com.iqiyi.pps.epg.core.utils.*;
import org.apache.commons.lang.StringUtils;
import org.apache.thrift.TException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.net.InetAddress;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Created by Administrator on 2014/12/4.
 */
@Component
public class ChannelStreamWebServiceImpl implements ChannelStreamWebService.Iface {

    private static Logger logger = LoggerFactory.getLogger(ChannelStreamWebServiceImpl.class);

    private LiveStreamService liveStreamService = null;
    private ChannelService channelService = null;
    private LiveChannelStreamService liveChannelStreamService = null;
    private EncodeService encodeService = null;

    private ISnapAsyncService getSnapAsyncService() {
        return WriteSystemLogUtil.getInstance().getSnapAsyncService();
    }

    @Override
    public String create(long fatherId, String streamName, String streamType, String streamIp, int peerCount, int bcsNum,
                         int cutterIdFlv, int cutterIdTs, String dest, int streamApiVersion, String dolbyStreamName,
                         String dolbyStreamUrl, String dolbyAudioChannel, int encodeType, String streamAddress, int playType, int backupEachOther) throws TException {
        logger.info("[ChannelStreamWebServiceImpl][create][Params:fatherId={},streamName={},streamType={},streamIp={},dolbyStreamName={},dolbyStreamUrl={}]",
                new Object[]{fatherId, streamName, streamType, streamIp, dolbyStreamName, dolbyStreamUrl});
        String code = null;
        try {
            LiveChannelStreamServiceImpl service = (LiveChannelStreamServiceImpl) ApplicationContextUtil.getBean(LiveChannelStreamServiceImpl.class);
            LiveChannelStream _liveChannelStream = null;
            boolean hasEnabledStream = false;
            if (peerCount <= LiveChannelStream.PEERCOUNT_MIN) {  //镜像服务器最小不能小于等于LiveChannelStream.PEERCOUNT_MIN
                code = Constants.CODE_ERROR_PEERCOUNT_MIN;
                return code;
            }
            if (peerCount >= LiveChannelStream.PEERCOUNT_MAX) {  //镜像服务器最大不能大于LiveChannelStream.PEERCOUNT_MAX
                code = Constants.CODE_ERROR_PEERCOUNT_MAX;
                return code;
            }

            if (bcsNum < LiveChannelStream.BCSNUM_MIN) { //广播源数量不能小于3
                code = Constants.CODE_ERROR_BCSNUM_MIN;
                return code;
            }

            if (bcsNum > LiveChannelStream.BCSNUM_MAX) { //广播源数量不能大于10
                code = Constants.CODE_ERROR_BCSNUM_MAX;
                return code;
            }

            if (encodeType < 0 || encodeType > 1) { // 流类型错误 (0: h264, 1: h265)
                code = Constants.CODE_ERROR_STREAM_ENCODETYPE;
                return code;
            }

            ChannelServiceImpl channelService = (ChannelServiceImpl) ApplicationContextUtil.getBean(ChannelServiceImpl.class);
            ChannelBase channelBase = channelService.getChannelBase(fatherId);
            if (channelBase == null) {    //频道还未创建
                code = Constants.CODE_ERROR_CHANNELBASE_NOT_EXIST;
                return code;
            }

            _liveChannelStream = service.get(streamName);
            if (_liveChannelStream != null) {  //流名称已存在
                code = Constants.CODE_ERROR_STREAMNAME_EXIST;
                return code;
            }

//            if(!streamName.endsWith("_jk")) {
//                _liveChannelStream = service.getByStreamType(fatherId, streamType);
//                if (_liveChannelStream != null) {   //该清晰度已存在
//                    code = Constants.CODE_ERROR_STREAMTYPE_EXIST;
//                    return code;
//                }
//            }

            if (StringUtils.isNotEmpty(dolbyStreamName)) {
                LiveChannelStream _dolbyLiveChannelStrema = service.getByDolbyStreamName(dolbyStreamName);
                if (_dolbyLiveChannelStrema != null) {
                    code = Constants.CODE_ERROR_DOLBYSTREAMNAME_EXIST;
                    return code;
                }
            }

            if (cutterIdFlv < 0 || cutterIdTs < 0) {
                code = Constants.CODE_ERROR;
                return code;
            }

            String universalCode = channelBase.getUniversalCode().toLowerCase();
            Integer liveType = channelBase.getLiveType();
            String pref = ChannelBase.LIVETYPE_MAP.get(liveType);
            StringBuffer checkStreamName = new StringBuffer();

            if (liveType == 1) { //常态直播，判断是否存在该流名称
                RtmpServiceImpl rtmpService = (RtmpServiceImpl) ApplicationContextUtil.getBean(RtmpServiceImpl.class);
                if (!rtmpService.isValidStream(streamName)) {
                    code = Constants.CODE_ERROR_STREAMNAME;
                    return code;
                }
                checkStreamName = new StringBuffer().append(pref).append("_").append(universalCode);
            } else if (liveType == 2 || liveType == 3) {   //临时直播
                checkStreamName = new StringBuffer().append(pref);
            }

            // 检查流名称命名规范
            if (streamName.indexOf(checkStreamName.toString()) < 0) {
                code = Constants.CODE_ERROR_STREAMNAME_SIGN;
                return code;
            }

            LiveChannelStream liveChannelStream = new LiveChannelStream();
            liveChannelStream.setFatherId(fatherId);
            liveChannelStream.setStreamName(streamName);
            liveChannelStream.setStreamType(streamType);
            liveChannelStream.setPeerCount(peerCount);
            liveChannelStream.setBcsNum(bcsNum);
            liveChannelStream.setCutterIdFlv(cutterIdFlv);
            liveChannelStream.setCutterIdTs(cutterIdTs);

            if (service.getByStreamTypeAndEncodeTypeWithIsEnable(fatherId, streamType, encodeType, true) != null) {
                liveChannelStream.setIsEnable(false);
                hasEnabledStream = true;
            } else {
                liveChannelStream.setIsEnable(true);
            }

            liveChannelStream.setRtmpSync(0);
            liveChannelStream.setDest(dest);
            liveChannelStream.setStreamApiVersion(
                    LiveChannelStream.STREAM_API_VERSION_MAP.containsKey(streamApiVersion) ? streamApiVersion : 0
            );
            if (streamIp != null) {
                liveChannelStream.setStreamIp(streamIp);
            }

            liveChannelStream.setDolbyStreamName(dolbyStreamName);
            liveChannelStream.setDolbyStreamUrl(dolbyStreamUrl);
            liveChannelStream.setDolbyAudioChannel(dolbyAudioChannel);

            liveChannelStream.setEncodeType(encodeType);
            liveChannelStream.setStreamAddress(streamAddress);
            liveChannelStream.setPlayType(playType);
            liveChannelStream.setBackupEachOther(backupEachOther);
            liveChannelStream.setSliceIndex(-1);


            liveChannelStream.setStreamUrls(
                    encodeType == LiveChannelStream.ENCODE_H265 ? streamAddress : liveChannelStream.fetchRtmpUrlUtil());

            liveChannelStream.setDolbyStreamUrls(dolbyStreamUrl);


            service.save(liveChannelStream);
            if (channelBase.getLiveType() == 2) {
                if (!hasEnabledStream) {
                    getSnapAsyncService().addStreamTask(liveChannelStream);
                }
                //临时直播，判断是否存在该流名称
                RtmpServiceImpl rtmpService = (RtmpServiceImpl) ApplicationContextUtil.getBean(RtmpServiceImpl.class);
                if (encodeType == LiveChannelStream.ENCODE_H264 && !rtmpService.isValidStream(streamName)) {
                    code = Constants.CODE_WARNING_STREAMNAME;

                    service.updateStreamUrlsBackup(liveChannelStream,true,liveChannelStream.getBackupEachOther() == 1);
                    return code;
                }

            }

            service.updateStreamUrlsBackup(liveChannelStream, true, liveChannelStream.getBackupEachOther() == 1);

            if (encodeType == LiveChannelStream.ENCODE_H265) {
                autoH265(liveChannelStream);
            }

            code = hasEnabledStream ? Constants.CODE_WARNING_STREAMTYPE_EXIST : Constants.CODE_SUC;
            return code;
        } catch (Exception e) {
            logger.error("[ChannelStreamWebServiceImpl][create][Exception={}]", e);
            return Constants.CODE_ERROR;
        } finally {
            logger.info("[ChannelStreamWebServiceImpl][create][End][Return:code={},codeValue={}]", new Object[]{code, Constants.getCode(code)});
        }
    }

    @Override
    public String deleteBy(long fatherId) throws TException {
        logger.info("[ChannelStreamWebServiceImpl][deleteBy][Params:fatherId={}]", new Object[]{fatherId});
        String code = null;
        try {
            LiveChannelStreamServiceImpl service = (LiveChannelStreamServiceImpl) ApplicationContextUtil.getBean(LiveChannelStreamServiceImpl.class);
            List<LiveChannelStream> liveChannelStreams = service.getByFatherId(fatherId);
            LiveStreamServiceImpl liveStreamService = (LiveStreamServiceImpl) ApplicationContextUtil.getBean(LiveStreamServiceImpl.class);
            for (LiveChannelStream liveChannelStream : liveChannelStreams) {
                liveStreamService.deleteQipu(liveChannelStream.getId(), fatherId, liveChannelStream.getStreamName(), null, liveChannelStream.getStreamApiVersion());
                service.delete(liveChannelStream);
            }
            code = Constants.CODE_SUC;
            return code;
        } catch (Exception e) {
            logger.error("[ChannelStreamWebServiceImpl][deleteBy][Exception={}]", e);
            return Constants.CODE_ERROR;
        } finally {
            logger.info("[ChannelStreamWebServiceImpl][deleteBy][End][Return:code={},codeValue={}]", new Object[]{code, Constants.getCode(code)});
        }
    }

    @Override
    public String deleteById(long liveChannelStreamId) throws TException {
        logger.info("[ChannelStreamWebServiceImpl][deleteById][Params:id={}]", new Object[]{liveChannelStreamId});
        String code = null;
        try {
            LiveChannelStreamServiceImpl service = (LiveChannelStreamServiceImpl) ApplicationContextUtil.getBean(LiveChannelStreamServiceImpl.class);
            LiveChannelStream liveChannelStream = service.getById(liveChannelStreamId);
            LiveStreamServiceImpl liveStreamService = (LiveStreamServiceImpl) ApplicationContextUtil.getBean(LiveStreamServiceImpl.class);
            if (liveChannelStream != null) {
                long fatherId = liveChannelStream.getFatherId();
                String streamName = liveChannelStream.getStreamName();
                if (service.count(fatherId) <= 1) {
                    int status = streamStatus(fatherId, streamName);
                    if (status == LiveChannelStream.STATUS_ACTIVED) {
                        code = Constants.CODE_ERROR_DELETE_LIVECHANNELSTREAM_LESS;
                        return code;
                    }
                }
                LiveStream stream = getDefaultFLVStream(liveChannelStream);
                service.delete(liveChannelStream);
                liveStreamService.deleteQipu(liveChannelStreamId, liveChannelStream.getFatherId(), liveChannelStream.getStreamName(), stream, liveChannelStream.getStreamApiVersion());

                service.updateStreamUrlsBackup(liveChannelStream,true,liveChannelStream.getBackupEachOther() == 1);
            }
            code = Constants.CODE_SUC;
            return code;
        } catch (Exception e) {
            logger.error("[ChannelStreamWebServiceImpl][deleteById][Exception={}]", e);
            return Constants.CODE_ERROR;
        } finally {
            logger.info("[ChannelStreamWebServiceImpl][deleteById][End][Return:code={},codeValue={}]", new Object[]{code, Constants.getCode(code)});
        }
    }

    private void deleteQipu(long id, long fatherId, String streamName, LiveStream defaultStream, int streamApiVersion) {
        LiveStreamServiceImpl liveStreamService = (LiveStreamServiceImpl) ApplicationContextUtil.getBean(LiveStreamServiceImpl.class);
//        LiveChannelStreamServiceImpl liveChannelStreamService = (LiveChannelStreamServiceImpl) ApplicationContextUtil.getBean(LiveChannelStreamServiceImpl.class);
//        List<LiveStream> liveStreams = liveStreamService.get(fatherId, streamName);
//        if (liveStreams != null && liveStreams.size() > 0) {
//            ChannelServiceImpl channelService = (ChannelServiceImpl) ApplicationContextUtil.getBean(ChannelServiceImpl.class);
//            for (LiveStream liveStream : liveStreams) {
//                //删除Qipu数据
//                if (liveStream.getStatus() != LiveStream.STATUS_DELETED) {
//
//                    Long qipuId = channelService.getQipuId(liveStream.getFatherId());
//                    if (qipuId > 0) {
//                        QipuManager qipuManager = (QipuManager) ApplicationContextUtil.getBean(QipuManager.class);
//                        qipuManager.delLiveStreamToQipu(qipuId, liveStream.getUuid());
//                        if (LiveStream.FORMATTYPE_FLV.equals(liveStream.getFormatType())) {
//                            //删除defaultLiveStreamToQipu数据
//                            qipuManager.setDefaultLiveStreamToQipu(qipuId, defaultStream);
//                        }
//                    }
//                }
//                //删除流数据
//                LiveStreamManager.deleteStream(liveStream, id);
//                //逻辑删除库中数据
//            //更新旧奇普
//              Long oldQipuId = channelService.getOldQipuId(fatherId);
//              if (oldQipuId > 0) {
//                  List<LiveChannelStream> liveChannelStreams = liveChannelStreamService.getByIsEnable(fatherId, true);
//                  liveStreamService.writeToTvQipu(fatherId, oldQipuId, liveChannelStreams);
//              }
//        }
    }

//    private JSONObject createStream(LiveStream liveStream, String liveChannelSteamIp, String streamIp, String peerCount, int sliceDelay) {
//        JSONObject jsonObject = null;
//        if (LiveStream.FORMATTYPE_FLV.equals(liveStream.getFormatType())) {
//            jsonObject = LiveStreamManager.createFlv(streamIp, liveStream.getStreamName(), peerCount, sliceDelay);
//        } else if (LiveStream.FORMATTYPE_TS.equals(liveStream.getFormatType())) {
//            jsonObject = LiveStreamManager.createTs(streamIp, liveStream.getStreamName(), sliceDelay);
//        } else if (LiveStream.FORMATTYPE_P2P.equals(liveStream.getFormatType())) {
//            jsonObject = LiveStreamManager.p2pOnline(streamIp, liveChannelSteamIp, liveStream.getStreamName(), peerCount);
//        }
//        return jsonObject;
//    }

    @Override
    public List<TChannelStream> getList(long fatherId) throws TException {
        Map<String, String> _rpcLog = new HashMap<>();
        List<TChannelStream> tChannelStreams = new ArrayList<TChannelStream>();

        try {
            _rpcLog.put("typeId", "2");
            _rpcLog.put("name", "_RPC.getList");
            _rpcLog.put("serverIp", InetAddress.getLocalHost().getHostAddress());
            _rpcLog.put("reqTime", String.valueOf(System.currentTimeMillis()));
            _rpcLog.put("appkey", "");
            _rpcLog.put("params", "fatherId=" + fatherId);

            LiveChannelStreamServiceImpl service = (LiveChannelStreamServiceImpl) ApplicationContextUtil.getBean(LiveChannelStreamServiceImpl.class);
            ChannelServiceImpl channelService = (ChannelServiceImpl) ApplicationContextUtil.getBean(ChannelServiceImpl.class);
            ChannelBase channelBase = channelService.getChannelBase(fatherId);
            List<LiveChannelStream> streams = service.getByFatherId(fatherId);
            for (LiveChannelStream stream : streams) {
                TChannelStream tChannelStream = new TChannelStream();
                tChannelStream.setId(stream.getId());
                tChannelStream.setFatherId(stream.getFatherId());
                tChannelStream.setChannelName(channelBase.getName());
                tChannelStream.setStreamName(stream.getStreamName());
                tChannelStream.setStreamIp(stream.getStreamIp());
                tChannelStream.setEncodedIp(stream.getEncodedIp());
                tChannelStream.setStatus(stream.getStatus().toString());
                tChannelStream.setInputBits(stream.getInputBits());
                tChannelStream.setOutputBits(stream.getOutputBits());
                tChannelStream.setStreamType(stream.getStreamType());
                tChannelStream.setBitRate(stream.getBitRate());
                tChannelStream.setAspectRatio(stream.getAspectRatio());
                tChannelStream.setScreenSize(stream.getScreenSize());
                tChannelStream.setFrameRate(stream.getFrameRate());
                tChannelStream.setVideo(stream.getVideo());
                tChannelStream.setAudio(stream.getAudio());
                tChannelStream.setPeerCount(stream.getPeerCount());
                tChannelStream.setBcsNum(stream.getBcsNum());
                tChannelStream.setCutterIdFlv(stream.getCutterIdFlv());
                tChannelStream.setCutterIdTs(stream.getCutterIdTs());
                if (stream.getIsEnable()) {
                    tChannelStream.setIsEnable("1");
                } else {
                    tChannelStream.setIsEnable("0");
                }
                tChannelStream.setAddTime(DateHelper.getDateStringByPattern(stream.getAddTime(), "yyyy-MM-dd HH:mm:ss"));
                tChannelStream.setUpdateTime(DateHelper.getDateStringByPattern(stream.getUpdateTime(), "yyyy-MM-dd HH:mm:ss"));
                tChannelStream.setDest(stream.getDest());
                tChannelStream.setStreamApiVersion(stream.getStreamApiVersion());
                tChannelStream.setDolbyStreamName(stream.getDolbyStreamName());
                tChannelStream.setDolbyStreamUrl(stream.getDolbyStreamUrl());
                tChannelStream.setDolbyAudioChannel(stream.getDolbyAudioChannel());
                tChannelStream.setEncodeType(stream.getEncodeType());
                tChannelStream.setStreamAddress(stream.getStreamAddress());
                tChannelStream.setStreamUrls(stream.getStreamUrls());
                tChannelStream.setDolbyStreamUrls(stream.getDolbyStreamUrls());
				tChannelStream.setPlayType(stream.getPlayType());
				tChannelStream.setBackupEachOther(stream.getBackupEachOther());
				tChannelStream.setSliceIndex(stream.getSliceIndex());
//                String privateIp = getPrivateIpByPublicIp(tChannelStream.getStreamIp());

                RtmpServer rtmpServer = getRtmpServerByPublicIp(tChannelStream.getStreamIp());

                if (null != rtmpServer) {
                    tChannelStream.setInternalIp(rtmpServer.getPrivateIp());
                    String outSignal = "rtmp://" + rtmpServer.getPrivateIp() + "/live/" + stream.getStreamName();
                    tChannelStream.setInputSignal(getInputsignalByOutsignal(outSignal));

                    tChannelStream.setPort(rtmpServer.getPort());
                } else {
                    tChannelStream.setInternalIp("");
                    tChannelStream.setInputSignal("");
                    tChannelStream.setPort(RtmpServer.PORT_DEFAULT);
                }

                tChannelStreams.add(tChannelStream);
            }
            return tChannelStreams;
        } catch (Exception e) {
            logger.error("[ChannelStreamWebServiceImpl][getList][Exception={}]", e);
            return tChannelStreams;
        } finally {
            _rpcLog.put("resTime", String.valueOf(System.currentTimeMillis()));
            _rpcLog.put("response", JSON.toJSONString(tChannelStreams));
            insertLog(_rpcLog);
        }
    }

    @Override
    public String edit(TChannelStream tChannelStream) throws TException {
        logger.info("[ChannelStreamWebServiceImpl][edit][Params:tChannelStream={}]", JSON.toJSONString(tChannelStream));
        String code = null;
        boolean isEnableChanged = false;
        try {
            LiveChannelStreamServiceImpl liveChannelStreamService = (LiveChannelStreamServiceImpl) ApplicationContextUtil.getBean(LiveChannelStreamServiceImpl.class);
            ChannelServiceImpl channelService = (ChannelServiceImpl) ApplicationContextUtil.getBean(ChannelServiceImpl.class);
            LiveChannelStream liveChannelStream = liveChannelStreamService.getById(tChannelStream.getId());
            LiveChannelStream _oldEnabledLiveChannelStream = null;
            if (liveChannelStream == null) {  //编码流数据不存在
                code = Constants.CODE_ERROR_LIVECHANNELSTREAM_NOT_EXIST;
                return code;
            }

//            if(!liveChannelStream.getStreamName().endsWith("_jk")) {
//                LiveChannelStream _liveChannelStream = liveChannelStreamService.getByStreamType(liveChannelStream.getFatherId(), tChannelStream.getStreamType(), liveChannelStream.getStreamName());
//                if (_liveChannelStream != null) {   //该清晰度已存在
//                    code = Constants.CODE_ERROR_STREAMTYPE_EXIST;
//                    return code;
//                }
//            }
            _oldEnabledLiveChannelStream = liveChannelStreamService.getByStreamTypeAndEncodeTypeWithIsEnable(
                    liveChannelStream.getFatherId(), tChannelStream.getStreamType(),
                    liveChannelStream.getEncodeType(), true);

            if (_oldEnabledLiveChannelStream != null && _oldEnabledLiveChannelStream.getId().equals(liveChannelStream.getId())) {
                _oldEnabledLiveChannelStream = null;
            }

            String streamIpBefore = liveChannelStream.getStreamIp();
            liveChannelStream.setStreamType(tChannelStream.getStreamType());
            liveChannelStream.setStreamIp(tChannelStream.getStreamIp());
            liveChannelStream.setPeerCount(tChannelStream.getPeerCount());
            liveChannelStream.setBcsNum(tChannelStream.getBcsNum());
            liveChannelStream.setCutterIdFlv(tChannelStream.getCutterIdFlv());
            liveChannelStream.setCutterIdTs(tChannelStream.getCutterIdTs());

            boolean _newIsEnable = tChannelStream.getIsEnable().equals("1");
            isEnableChanged = _newIsEnable != liveChannelStream.getIsEnable();

            if ("1".equals(tChannelStream.getIsEnable())) {
                liveChannelStream.setIsEnable(true);
            } else {
                liveChannelStream.setIsEnable(false);
            }
            liveChannelStream.setDest(tChannelStream.getDest());
            liveChannelStream.setStreamApiVersion(tChannelStream.getStreamApiVersion());
            liveChannelStream.setUpdateTime(new Timestamp(System.currentTimeMillis()));

            boolean playTypeChannge = false;
            if (liveChannelStream.getPlayType() != tChannelStream.getPlayType() && liveChannelStream.getPlayType() == LiveChannelStream.PLAY_TYPE_TIMING) {
                playTypeChannge = true;
            }
            liveChannelStream.setPlayType(tChannelStream.getPlayType());

            //互为灾备发生变化, 流策略需要更新
            boolean isBackupEachOtherChanged = false;
            if (liveChannelStream.getBackupEachOther() != tChannelStream.getBackupEachOther()) {
                isBackupEachOtherChanged = true;
            }
            liveChannelStream.setBackupEachOther(tChannelStream.getBackupEachOther());

            // 临时频道RTMP地址发生改变
            ChannelBase channelBase = channelService.getChannelBase(tChannelStream.getFatherId());
            if (channelBase.getLiveType() == 2 && StringUtils.isNotEmpty(streamIpBefore) && !streamIpBefore.equals(tChannelStream.getStreamIp())) {
                return LiveStreamManager.rtmpChanged(liveChannelStream, tChannelStream.getStreamIp());
            }

            liveChannelStreamService.edit(liveChannelStream);

            // 更新上下线状态
            liveChannelStreamService.updateChannelStreamIsEnable(liveChannelStream, tChannelStream.getIsEnable());

            LiveStreamServiceImpl liveStreamService = (LiveStreamServiceImpl) ApplicationContextUtil.getBean(LiveStreamServiceImpl.class);
            List<LiveStream> liveStreams = liveStreamService.get(liveChannelStream.getFatherId(), liveChannelStream.getStreamName());

            if (null != _oldEnabledLiveChannelStream && tChannelStream.getIsEnable().equals("1")
                    && channelBase.getQipuId() > 0 && isEnableChanged) {
                offlineLiveChannelStream(liveChannelStreamService, _oldEnabledLiveChannelStream, liveStreamService, channelBase.getQipuId());
            }

            // playType发生变化时要修改 HLFLV的URL参数hl_pltp
            if (playTypeChannge) {
                for (LiveStream liveStream : liveStreams) {
                    if (LiveStream.FORMATTYPE_HLFLV.equals(liveStream.getFormatType())) {
                        String replaceParam = "hl_pltp=" + liveChannelStream.getPlayType();
                        String url = liveStream.getUrl();
                        liveStream.setUrl(url.replaceAll("hl_pltp=\\d{1}", replaceParam));
                        liveStreamService.save(liveStream);
                        break;
                    }
                }
            }

            if (isBackupEachOtherChanged) {
                liveChannelStreamService.updateStreamUrlsBackup(liveChannelStream,false,true);
            }
            if (liveStreams != null && liveStreams.size() > 0) {
                if (channelBase.getQipuId() > 0) {
                    getSnapAsyncService().addStreamTask(liveChannelStream);
                    dealNotifyQipu(liveChannelStreamService, liveChannelStream, liveStreamService, liveStreams, channelBase.getQipuId(), tChannelStream.getIsEnable().equals("1"));
                }

            }

            code = (_oldEnabledLiveChannelStream == null || (!tChannelStream.getIsEnable().equals("1") && isEnableChanged) || !isEnableChanged)
                    ? Constants.CODE_SUC : Constants.CODE_WARNING_STREAMTYPE_ENABLED_AUTOOFFLINE;
            return code;
        } catch (Exception e) {
            logger.error("[ChannelStreamWebServiceImpl][edit][Exception={}]", e);
            return Constants.CODE_ERROR;
        } finally {
            logger.info("[ChannelStreamWebServiceImpl][edit][End][Return:code={},codeValue={}]", new Object[]{code, Constants.getCode(code)});
        }
    }

    private void offlineLiveChannelStream(LiveChannelStreamServiceImpl liveChannelStreamService, LiveChannelStream liveChannelStream, LiveStreamServiceImpl liveStreamService, Long qipuId) {
        logger.info("[offlineLiveChannelStream][liveChannelStream={}][qipuId={}]", JSON.toJSONString(liveChannelStream), qipuId + "");
        QipuManager qipuManager = (QipuManager) ApplicationContextUtil.getBean(QipuManager.class);
        List<String> delList = new ArrayList<>();
        LiveStream defaultStream = null;
        List<LiveStream> liveStreams = liveStreamService.get(liveChannelStream.getFatherId(), liveChannelStream.getStreamName());

//        liveChannelStream.setIsEnable(false);
//        liveChannelStreamService.edit(liveChannelStream);
        liveChannelStreamService.updateChannelStreamIsEnable(liveChannelStream, "0");

        for (LiveStream liveStream : liveStreams) {
            delList.add(liveStream.getUuid());
//            if(LiveStream.FORMATTYPE_FLV.equals(liveStream.getFormatType()) && liveStream.getIsDefault()) {
//                LiveStream defaultLiveStream = getDefaultFLVStream(liveChannelStream);
//                defaultStream = defaultLiveStream;
//                if(null == defaultLiveStream){
//                    liveStream.setIsDefault(true);
//                }else{
//                    liveStream.setIsDefault(false);
//                }
//                liveStreamService.edit(liveStream);
//            }
        }
        int rest = qipuManager.updateLiveStreamsToQipu(qipuId, new ArrayList<LiveStream>(), delList, defaultStream);
        logger.info("[offlineLiveChannelStream][updateLiveStreamsToQipu][qipuId={}][rest={}]", qipuId, rest);
    }

    private void dealNotifyQipu(LiveChannelStreamServiceImpl liveChannelStreamService, LiveChannelStream liveChannelStream, LiveStreamServiceImpl liveStreamService,
                                List<LiveStream> liveStreams, Long qipuId, boolean isEnable) {
        QipuManager qipuManager = (QipuManager) ApplicationContextUtil.getBean(QipuManager.class);
        List<LiveStream> addList = new ArrayList<LiveStream>();
        List<String> delList = new ArrayList<String>();
        LiveStream defaultStream = null;

        for (LiveStream liveStream : liveStreams) {
            if (isEnable) { // 是否同步奇谱
                addList.add(liveStream);
//                if(LiveStream.FORMATTYPE_FLV.equals(liveStream.getFormatType())){
//                    if(liveStream.getIsDefault()) {
//                        defaultStream = liveStream;
//                    }else{
//                        LiveStream defaultLiveStream = liveStreamService.getByDefault(liveChannelStream.getFatherId(), LiveStream.FORMATTYPE_FLV, true);
//                        if (null != defaultLiveStream) {
//                            LiveChannelStream defaultLiveChannelStream = liveChannelStreamService.get(defaultLiveStream.getFatherId(), defaultLiveStream.getStreamName());
//                            if(!defaultLiveChannelStream.getIsEnable()){
//                                defaultLiveStream.setIsDefault(false);
//                                liveStreamService.edit(defaultLiveStream);
//                                liveStream.setIsDefault(true);
//                                liveStreamService.edit(liveStream);
//                                defaultStream = liveStream;
//                            } else {
//                                defaultStream = defaultLiveStream;
//                            }
//                        }else{
//                            liveStream.setIsDefault(true);
//                            liveStreamService.edit(liveStream);
//                            defaultStream = liveStream;
//                        }
//                    }
//                }
            } else {
                //qipuManager.delLiveStreamToQipu(qipuId, liveStream.getUuid());
                delList.add(liveStream.getUuid());
//                if(LiveStream.FORMATTYPE_FLV.equals(liveStream.getFormatType()) && liveStream.getIsDefault()){
//                    LiveStream defaultLiveStream = getDefaultFLVStream(liveChannelStream);
//                    defaultStream = defaultLiveStream;
//                    if(null == defaultLiveStream){
//                        liveStream.setIsDefault(true);
//                        liveStreamService.edit(liveStream);
//                    }
//                }
            }
        }
        int rest = qipuManager.updateLiveStreamsToQipu(qipuId, addList, delList, defaultStream);
        logger.info("[updateLiveStreamsToQipu][qipuId={}][rest={}]", qipuId, rest);
    }

    @Override
    public TChannelStream getById(long id) throws TException {
        logger.info("[ChannelStreamWebServiceImpl][getById][Params:id={}]", id);
        LiveChannelStreamServiceImpl service = (LiveChannelStreamServiceImpl) ApplicationContextUtil.getBean(LiveChannelStreamServiceImpl.class);
        LiveChannelStream liveChannelStream = service.getById(id);
        if (liveChannelStream != null) {
            TChannelStream tChannelStream = new TChannelStream();
            tChannelStream.setId(liveChannelStream.getId());
            tChannelStream.setFatherId(liveChannelStream.getFatherId());
            tChannelStream.setStreamName(liveChannelStream.getStreamName());
            tChannelStream.setStreamIp(liveChannelStream.getStreamIp());
            tChannelStream.setEncodedIp(liveChannelStream.getEncodedIp());
            tChannelStream.setStatus(liveChannelStream.getStatus().toString());
            tChannelStream.setInputBits(liveChannelStream.getInputBits());
            tChannelStream.setOutputBits(liveChannelStream.getOutputBits());
            tChannelStream.setStreamType(liveChannelStream.getStreamType());
            tChannelStream.setBitRate(liveChannelStream.getBitRate());
            tChannelStream.setAspectRatio(liveChannelStream.getAspectRatio());
            tChannelStream.setScreenSize(liveChannelStream.getScreenSize());
            tChannelStream.setPeerCount(liveChannelStream.getPeerCount());
            if (liveChannelStream.getIsEnable()) {
                tChannelStream.setIsEnable("1");
            } else {
                tChannelStream.setIsEnable("0");
            }
            tChannelStream.setAddTime(DateHelper.getDateStringByPattern(liveChannelStream.getAddTime(), "yyyy-MM-dd HH:mm:ss"));
            tChannelStream.setUpdateTime(DateHelper.getDateStringByPattern(liveChannelStream.getUpdateTime(), "yyyy-MM-dd HH:mm:ss"));

            tChannelStream.setDolbyStreamName(liveChannelStream.getDolbyStreamName());
            tChannelStream.setDolbyStreamUrl(liveChannelStream.getDolbyStreamUrl());
            tChannelStream.setDolbyAudioChannel(liveChannelStream.getDolbyAudioChannel());
            tChannelStream.setEncodeType(liveChannelStream.getEncodeType());
            tChannelStream.setStreamAddress(liveChannelStream.getStreamAddress());
            tChannelStream.setSliceIndex(liveChannelStream.getSliceIndex());

            logger.info("[ChannelStreamWebServiceImpl][getById][Return:tChannelStream={}]", JSON.toJSONString(tChannelStream));
            return tChannelStream;
        }
        return null;
    }

    @Override
    public TStreamInfoSuggest streamInfoSuggest(long fatherId, String streamName) throws TException {
        logger.info("[ChannelStreamWebServiceImpl][streamInfoSuggest][Params:fatherId={}, streamName={}]", fatherId, streamName);
        TStreamInfoSuggest tStreamInfoSuggest = new TStreamInfoSuggest();
        List<TStreamInfo> tStreamInfos = new ArrayList<TStreamInfo>();
        RtmpServiceImpl rtmpService = (RtmpServiceImpl) ApplicationContextUtil.getBean(RtmpServiceImpl.class);
        List<RtmpServerStat> list = rtmpService.streamInfoSuggest(streamName);
        if (list != null) {
            for (RtmpServerStat rtmpServerStat : list) {
                TStreamInfo tStreamInfo = new TStreamInfo();
                tStreamInfo.setStreamName(rtmpServerStat.getName());
                tStreamInfo.setStreamIp(rtmpServerStat.getAddress());
                tStreamInfos.add(tStreamInfo);
            }
            ChannelServiceImpl channelService = (ChannelServiceImpl) ApplicationContextUtil.getBean(ChannelServiceImpl.class);
            ChannelBase channelBase = channelService.getChannelBase(fatherId);
            tStreamInfoSuggest.setLiveType(channelBase.getLiveType() + "");
            tStreamInfoSuggest.setStreamInfoList(tStreamInfos);
        }
        logger.info("[ChannelStreamWebServiceImpl][streamInfoSuggest][Return:tStreamInfoSuggest={}]", JSON.toJSONString(tStreamInfoSuggest));
        return tStreamInfoSuggest;
    }

    @Override
    public String restart(long fatherId, String streamName, String newStreamIp) throws TException {
        logger.info("[ChannelStreamWebServiceImpl][restart][Params:fatherId={}, streamName={}]", fatherId, streamName);
        String code = null;
        try {
            LiveChannelStreamServiceImpl service = (LiveChannelStreamServiceImpl) ApplicationContextUtil.getBean(LiveChannelStreamServiceImpl.class);
            LiveChannelStream liveChannelStream = service.get(fatherId, streamName);
            LiveStreamManager liveStreamManager = (LiveStreamManager) ApplicationContextUtil.getBean(LiveStreamManager.class);
            if (liveChannelStream == null) {  //编码流数据不存在
                code = Constants.CODE_ERROR_LIVECHANNELSTREAM_NOT_EXIST;
                return code;
            }
            if (!liveChannelStream.getStreamIp().equals(newStreamIp)) {
                liveStreamManager.rtmpChanged(liveChannelStream, newStreamIp);
            }
            code = Constants.CODE_SUC;
            return code;
        } catch (Exception e) {
            logger.error("[ChannelStreamWebServiceImpl][restart][Exception={}]", e);
            return Constants.CODE_ERROR;
        } finally {
            logger.info("[ChannelStreamWebServiceImpl][restart][End][Return:code={},codeValue={}]", new Object[]{code, Constants.getCode(code)});
        }
    }

    @Override
    public int streamStatus(long fatherId, String streamName) throws TException {
        logger.info("[ChannelStreamWebServiceImpl][streamState][Params:fatherId={}]", fatherId);
        int status = LiveChannelStream.STATUS_IDLED;
        try {
            LiveChannelStreamService liveChannelStreamService = (LiveChannelStreamService) ApplicationContextUtil.getBean(LiveChannelStreamService.class);
            if (StringUtils.isEmpty(streamName)) {
                List<LiveChannelStream> streams = liveChannelStreamService.getByFatherId(fatherId);
                if (streams != null && streams.size() > 0) {
                    for (LiveChannelStream stream : streams) {
                        status = stream.getStatus();
                        if (status == LiveChannelStream.STATUS_ACTIVED) {
                            return status;
                        } else {
                            continue;
                        }
                    }
                } else {
                    return status = LiveChannelStream.STATUS_DELETE;
                }
            } else {
                LiveChannelStream stream = liveChannelStreamService.get(fatherId, streamName);
                if (stream != null) {
                    return status = stream.getStatus();
                }
            }

            return status;
        } finally {
            logger.info("[ChannelStreamWebServiceImpl][streamState][End][Return:status={}]", status);
        }
    }

    private String getPrivateIpByPublicIp(String publicIp) {
        if (null == publicIp || "".equals(publicIp)) {
            return "";
        }

        RtmpService rtmpService = (RtmpService) ApplicationContextUtil.getBean(RtmpService.class);

        try {
            RtmpServer rtmpServer = rtmpService.getByPublicIp(publicIp);
            if (null == rtmpServer || null == rtmpServer.getPrivateIp()) {
                return "";
            }

            return rtmpServer.getPrivateIp();
        } catch (Exception e) {
            logger.info("[ChannelStreamWebServiceImpl][getPrivateIpByPublicIp][publicIp={}][failed]", publicIp);
            return "";
        }
    }

    private RtmpServer getRtmpServerByPublicIp(String publicIp) {
        if (null == publicIp || "".equals(publicIp)) {
            return null;
        }

        RtmpService rtmpService = (RtmpService) ApplicationContextUtil.getBean(RtmpService.class);

        try {
            return rtmpService.getByPublicIp(publicIp);
        } catch (Exception e) {
            logger.info("[ChannelStreamWebServiceImpl][getRtmpServerByPublicIp][publicIp={}][failed]", publicIp);
            return null;
        }
    }

    @Override
    public TLiveStream getDefaultFLVStreamByName(long fatherId, String streamName) throws TException {
        return null;
//        LiveChannelStreamServiceImpl service = (LiveChannelStreamServiceImpl) ApplicationContextUtil.getBean(LiveChannelStreamServiceImpl.class);
//        LiveChannelStream liveChannelStream = service.get(fatherId, streamName);
//
//        if (null == liveStreamService) {
//            liveStreamService = (LiveStreamServiceImpl) ApplicationContextUtil.getBean(
//                    LiveStreamService.class);
//        }
//
//        LiveStream defaultStream = null;
//
//        try {
//            defaultStream = getNextDefaultStream(liveChannelStream);
//
//            if (null == defaultStream) {
//                logger.info("[ChannelStreamWebServiceImpl][getDefaultFLVStreamByName][no next available stream exists]");
//            } else {
//                defaultStream.setIsDefault(true);
//                liveStreamService.edit(defaultStream);
//            }
//        } catch (Exception e) {
//            logger.info("[ChannelStreamWebServiceImpl][getDefaultFLVStreamByName][failed]");
//        }
//
//        return transferLiveStream(defaultStream);
    }

    private TLiveStream transferLiveStream(LiveStream liveStream) {
        if (null == liveStream) {
            return null;
        }

        TLiveStream result = new TLiveStream();
        result.setId(liveStream.getId());
        result.setFatherId(liveStream.getFatherId());
        result.setStreamName(liveStream.getStreamName());
        result.setIsDefault(liveStream.getIsDefault() ? "1" : "0");
        result.setUuid(liveStream.getUuid());
        result.setUrl(liveStream.getUrl());
        result.setFormatType(liveStream.getFormatType());
        result.setStatus(liveStream.getStatus());
        result.setAddTime(null != liveStream.getAddTime() ? String.valueOf(liveStream.getAddTime().getTime()) : null);
        result.setUpdateTime(null != liveStream.getUpdateTime() ? String.valueOf(liveStream.getUpdateTime().getTime()) : null);

        return result;
    }

    private LiveStream getDefaultFLVStream(LiveChannelStream current) {
        return null;
//        try {
//            if(null == liveStreamService) {
//                liveStreamService = (LiveStreamServiceImpl) ApplicationContextUtil.getBean(
//                        LiveStreamService.class);
//            }
//
//            LiveStream _liveStream = liveStreamService.get(
//                    current.getFatherId(), current.getStreamName(), LiveStream.FORMATTYPE_FLV);
//            if (null == _liveStream || !_liveStream.getIsDefault()) {
//                return liveStreamService.getByDefault(current.getFatherId(), LiveStream.FORMATTYPE_FLV, true);
//            }
//
//            _liveStream.setIsDefault(false);
//            liveStreamService.edit(_liveStream);
//
//            LiveStream defaultStream = getNextDefaultStream(current);
//
//            if(null == defaultStream){
//                logger.info("[ChannelStreamWebServiceImpl][resetDefaultStream][no next available stream exists]");
//            }else {
//                defaultStream.setIsDefault(true);
//                liveStreamService.edit(defaultStream);
//            }
//
//            return defaultStream;
//        }catch (Exception e){
//            logger.info("[ChannelStreamWebServiceImpl][resetDefaultStream][fatherId={}][streamName={}][failed]",
//                    current.getFatherId(), current.getStreamName());
//            return null;
//        }
    }

    private LiveStream getNextDefaultStream(LiveChannelStream current) throws Exception {
        long fatherId = current.getFatherId();
        if (null == liveChannelStreamService) {
            liveChannelStreamService = (LiveChannelStreamServiceImpl) ApplicationContextUtil.getBean(LiveChannelStreamServiceImpl.class);
        }
        List<LiveChannelStream> streams = liveChannelStreamService.getByIsEnable(fatherId, true);

        Collections.sort(streams, new StreamOrderComparator(getStreamTypes()));

        List<LiveChannelStream> lowerList = new ArrayList<>();
        List<LiveChannelStream> higherList = new ArrayList<>();

        for (int i = 0; i < streams.size(); ++i) {
            LiveChannelStream temp = streams.get(i);
            if (temp.getId().longValue() != current.getId().longValue()) {
                lowerList.add(temp);
                streams.remove(i);
                --i;
            } else {
                streams.remove(temp);
                break;
            }
        }

        higherList = streams;

        int _lowerSize = lowerList.size();
        int _higherSize = higherList.size();

        if (_lowerSize == 0 && _higherSize == 0) {
            return null;
        }

        // The current LiveChannelStream is at the very beginning.
        if (_lowerSize == 0) {
            return getStreamNotMiddle(higherList);
        }

        // The current LiveChannelStream is at the end.
        if (_higherSize == 0) {
            Collections.sort(lowerList, new StreamOrderComparator(getStreamTypes(), StreamOrderComparator.DESC));
            return getStreamNotMiddle(lowerList);
        }

        // The current LiveChannelStream is in the middle.
        int size = _lowerSize > _higherSize ? _lowerSize : _higherSize;

        LiveStream alternate = null;
        for (int i = 0; i < size; ++i) {
            LiveChannelStream temp = null;
            LiveStream stream = null;

            if (i < _lowerSize) {
                temp = lowerList.get(_lowerSize - i - 1);
                stream = getFlvStream(temp);
                if (temp.getStatus() == LiveChannelStream.STATUS_ACTIVED && null != stream) {
                    return stream;
                }

                if (stream != null && null == alternate) {
                    alternate = stream;
                }

            }

            if (i < _higherSize) {
                temp = higherList.get(i);
                stream = getFlvStream(temp);
                if (temp.getStatus() == LiveChannelStream.STATUS_ACTIVED && null != stream) {
                    return stream;
                }

                if (stream != null && null == alternate) {
                    alternate = stream;
                }
            }
        }

        return alternate;
    }

    private LiveStream getStreamNotMiddle(List<LiveChannelStream> list) throws Exception {
        LiveStream alternate = null;
        for (LiveChannelStream temp : list) {
            LiveStream stream = getFlvStream(temp);
            if (temp.getStatus().intValue() == LiveChannelStream.STATUS_ACTIVED && null != stream) {
                return stream;
            }

            if (stream != null && null == alternate) {
                alternate = stream;
            }
        }

        return alternate;
    }

    // if has default livestream return livestream otherwise null.
    private LiveStream getFlvStream(LiveChannelStream current) throws Exception {
        if (null == liveStreamService) {
            liveStreamService = (LiveStreamService) ApplicationContextUtil.getBean(
                    LiveStreamService.class);
        }
        LiveStream _liveStream = liveStreamService.get(
                current.getFatherId(), current.getStreamName(), LiveStream.FORMATTYPE_FLV);
        return _liveStream;
    }

    // Get streamTypes from the table of channel_config with the type "StreamType".
    private Map<String, Integer> getStreamTypes() throws Exception {
        Map<String, Integer> streamTypes = new HashMap<>();

        if (null == channelService) {
            channelService = (ChannelService) ApplicationContextUtil.getBean(ChannelService.class);
        }
        List<ChannelConfig> channelConfigs = channelService.getConfig("StreamType");

        for (ChannelConfig temp : channelConfigs) {
            streamTypes.put(temp.getVal(), temp.getKey());
        }

        return streamTypes;
    }

    private String getInputsignalByOutsignal(String outsignal) {
        EncodeServiceImpl service = (EncodeServiceImpl) ApplicationContextUtil.getBean(EncodeServiceImpl.class);
        String result = service.findInputsignalByOutputsignal(outsignal);
        return null == result ? "" : result;
    }

    private void insertLog(Map<String, String> logData) {
        InterfaceLogService service = (InterfaceLogService) ApplicationContextUtil.getBean(InterfaceLogService.class);
        InterfaceLog interfaceLog = JSONObject.parseObject(JSON.toJSONString(logData), InterfaceLog.class);
        interfaceLog.setPlatform(Byte.valueOf("1"));
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Long usageTime = (interfaceLog.getResTime().getTime() - interfaceLog.getReqTime().getTime()) / 1000;
        interfaceLog.setUsageTime(usageTime.intValue());
        if (interfaceLog.getAppkey() == null) {
            interfaceLog.setAppkey("");
        }
        service.save(interfaceLog);
    }

    private boolean autoH265(LiveChannelStream liveChannelStream) {
        logger.info("[autoH265][livechannelStream={}]", JSON.toJSONString(liveChannelStream));

        updateLiveChannelStream(liveChannelStream);

        String code = LiveStreamManager.newTs(liveChannelStream.getFatherId(), liveChannelStream.getStreamName());
        logger.info("[autoH265][livechannelStream={}][code={}]", liveChannelStream.getId(), code);

        return code.equals(Constants.CODE_SUC);
    }

    private void updateLiveChannelStream(LiveChannelStream liveChannelStream) {
        logger.info("[updateLiveChannelStream][livechannelstream={}]", JSON.toJSONString(liveChannelStream));
        try {
            EncodeService encodeService = (EncodeService) ApplicationContextUtil.getBean(EncodeService.class);
            LiveChannelStreamServiceImpl service = (LiveChannelStreamServiceImpl) ApplicationContextUtil.getBean(LiveChannelStreamServiceImpl.class);

            EncodeServer encodeServer = encodeService.getByOutputsignal(liveChannelStream.getStreamAddress());

            if (null == encodeServer) {
                return;
            }

            liveChannelStream.setEncodedIp(encodeServer.getServerIp());

            String extraInfo = encodeServer.getExtraData();
            if (StringUtils.isEmpty(extraInfo)) {
                return;
            }

            extraInfo = extraInfo.replace("\\:", ":");
            JSONObject info = JSONObject.parseObject(extraInfo);

            if (null == info) {
                return;
            }


            if (info.containsKey("inputBits")) {
                liveChannelStream.setInputBits(info.getString("inputBits"));
            }

            if (info.containsKey("outputBits")) {
                liveChannelStream.setOutputBits(info.getString("outputBits"));
            }

            if (info.containsKey("frameRate")) {
                liveChannelStream.setFrameRate(info.getString("frameRate"));
            }

            if (info.containsKey("bitRate")) {
                liveChannelStream.setBitRate(info.getLong("bitRate"));
            }

            if (info.containsKey("video")) {
                liveChannelStream.setVideo(info.getString("video"));
            }

            if (info.containsKey("audio")) {
                liveChannelStream.setAudio(info.getString("audio"));
            }

            if (info.containsKey("screenSize")) {
                liveChannelStream.setScreenSize(
                        info.getString("screenSize")
                                .replace("X", ":")
                                .replace("x", ":"));
            }

            if (info.containsKey("aspectRatio")) {
                liveChannelStream.setAspectRatio(info.getString("aspectRatio"));
            }

            liveChannelStream.setStatus(LiveChannelStream.STATUS_ACTIVED);

            service.save(liveChannelStream);
        } catch (Exception e) {
            logger.info("[updateLiveChannelStream][except={}]" + e);
        }
    }

    @Override
    public TChannelStreamPage getSearchList(TPage page, TFilter filter) {
        LiveChannelStreamService service = (LiveChannelStreamService) ApplicationContextUtil.getBean(LiveChannelStreamService.class);
        TChannelStreamPage tChannelStreamPage = service.getSearchList(page, filter);
        return tChannelStreamPage;
    }

    @Override
    public int switchBackup(long fatherId, long qipuId, String opUser) {
        try {
            LiveChannelStreamService channelStreamService = (LiveChannelStreamService) ApplicationContextUtil.getBean(
                    LiveChannelStreamService.class);

            List<LiveChannelStream> channelStreamList = channelStreamService.getByFatherId(fatherId);
            if (!operateSwitchBackup(channelStreamList, qipuId, fatherId, opUser)) {
                return -1;
            }

            return 0;
        } catch (Exception e) {
            logger.info("[switchBackup] exception ", e);
            return -2;
        }
    }

    private boolean operateSwitchBackup(List<LiveChannelStream> streamList, long qipuId, long fatherId, String opUser) {
        logger.info("[operateSwitchBackup][qipuId={}][fatherId={}]", qipuId, fatherId);
        int size = streamList.size();
        if (size == 0 || size % 2 == 1) {
            return false;
        }

        List<LiveChannelStream> enabedList = new ArrayList<>();
        List<LiveChannelStream> disabledList = new ArrayList<>();
        Map<String, Integer> streamTypeCounts = new HashMap<>();

        List<LiveChannelStream> enabedList265 = new ArrayList<>();
        List<LiveChannelStream> disabledList265 = new ArrayList<>();
        Map<String, Integer> streamTypeCounts265 = new HashMap<>();

        try {
            for (LiveChannelStream channelStream : streamList) {
                if (channelStream.getStatus() != LiveChannelStream.STATUS_ACTIVED) {
                    continue;
                }

                if (channelStream.getIsEnable()) {
                    if (channelStream.getEncodeType() == LiveChannelStream.ENCODE_H265) {
                        enabedList265.add(channelStream);
                    } else {
                        enabedList.add(channelStream);
                    }
                } else {
                    if (channelStream.getEncodeType() == LiveChannelStream.ENCODE_H265) {
                        disabledList265.add(channelStream);
                    } else {
                        disabledList.add(channelStream);
                    }
                }

                if (channelStream.getEncodeType() == LiveChannelStream.ENCODE_H265) {
                    Integer count = streamTypeCounts265.get(channelStream.getStreamType());
                    streamTypeCounts265.put(channelStream.getStreamType(), null == count ? 1 : count + 1);
                } else {
                    Integer count = streamTypeCounts.get(channelStream.getStreamType());
                    streamTypeCounts.put(channelStream.getStreamType(), null == count ? 1 : count + 1);
                }
            }

            if (enabedList.size() + enabedList265.size() != size / 2 ||
                    disabledList.size() + disabledList265.size() != size / 2) {
                return false;
            }
            logger.info("[operateSwitchBackup][qipuId={}][fatherId={}][list finished]", qipuId, fatherId);

            // make sure one-enabled and one-disabled
            Iterator<Map.Entry<String, Integer>> iter = streamTypeCounts.entrySet().iterator();
            while (iter.hasNext()) {
                Map.Entry<String, Integer> entry = iter.next();
                if (entry.getValue() != 2) {
                    return false;
                }

            }

            iter = streamTypeCounts265.entrySet().iterator();
            while (iter.hasNext()) {
                Map.Entry<String, Integer> entry = iter.next();
                if (entry.getValue() != 2) {
                    return false;
                }

            }

        } catch (Exception e) {
            logger.info("[operateSwitchBackup] e = " + e);
            return false;
        }

        // merge two types of lists
        enabedList.addAll(enabedList265);
        disabledList.addAll(disabledList265);

        logger.info("[operateSwitchBackup][qipuId={}][fatherId={}][finished]", qipuId, fatherId);
        return doSwitchBackup(enabedList, disabledList, qipuId, fatherId, opUser);
    }

    private String extractIds(List<LiveChannelStream> list) {
        StringBuffer sb = new StringBuffer();
        for (LiveChannelStream stream : list) {
            sb.append(stream.getId());
        }
        return sb.toString();
    }

    private boolean doSwitchBackup(List<LiveChannelStream> enabledList, List<LiveChannelStream> disabledList, long qipuId,
                                   long fatherId, String opUser) {
        logger.info("[doSwitchBackup][enabledList={}][disabledList={}][qipuId={}]",
                extractIds(enabledList), extractIds(disabledList), qipuId);

        StringBuilder onlineStreams = new StringBuilder();
        StringBuilder offlineStreams = new StringBuilder();

        try {
            LiveChannelStreamService channelStreamService = (LiveChannelStreamService) ApplicationContextUtil.getBean(
                    LiveChannelStreamService.class);
            LiveStreamService streamService = (LiveStreamService) ApplicationContextUtil.getBean(LiveStreamService.class);

            QipuManager qipuManager = (QipuManager) ApplicationContextUtil.getBean(QipuManager.class);

            List<String> delList = new ArrayList<>();
            List<LiveStream> addList = new ArrayList<>();

            // offline enabled streams
            for (LiveChannelStream liveChannelStream : enabledList) {
                channelStreamService.updateChannelStreamIsEnable(liveChannelStream, "0");

                List<LiveStream> liveStreams = streamService.get(
                        liveChannelStream.getFatherId(), liveChannelStream.getStreamName());

                for (LiveStream stream : liveStreams) {
                    delList.add(stream.getUuid());
                }
                offlineStreams.append(liveChannelStream.getStreamName()).append(",");

            }

            // online disabled streams
            for (LiveChannelStream liveChannelStream : disabledList) {
                channelStreamService.updateChannelStreamIsEnable(liveChannelStream, "1");

                List<LiveStream> liveStreams = streamService.get(
                        liveChannelStream.getFatherId(), liveChannelStream.getStreamName());

                for (LiveStream stream : liveStreams) {
                    addList.add(stream);
                }
                onlineStreams.append(liveChannelStream.getStreamName()).append(",");
            }

            logger.info("[doSwitchBackup][write qipu][start]");
            int result = qipuManager.updateLiveStreamsToQipu(qipuId, addList, delList, null);
            writeChannelLog(fatherId, Constants.LogType.ONKEY_SWITCH_STREAM.getIndex(), opUser,
                    String.format("操作成功|上线[%s], 下线[%s]", onlineStreams.toString(), offlineStreams.toString()));

            logger.info("[doSwitchBackup][finished][result={}]", result);
        } catch (Exception e) {
            logger.info("[doSwitchBackup][error][exception={}]", e);
            return false;
        }

        return true;
    }

    private void writeChannelLog(long channelId, int type, String user, String descr) {
        WriteSystemLogUtil.getInstance().writeChannelLog(channelId, type, user, descr);

    }

    @Override
    public TChannelStream notifyChange(String streamName, String sliceIndex) {
        try {
            LiveChannelStreamServiceImpl service = (LiveChannelStreamServiceImpl) ApplicationContextUtil.getBean(LiveChannelStreamServiceImpl.class);
            LiveChannelStream liveChannelStream = service.get(streamName);
            if (null != liveChannelStream) {
                liveChannelStream.setSliceIndex(Integer.parseInt(sliceIndex));
                service.edit(liveChannelStream);
                TChannelStream tChannelStream = new TChannelStream();
                tChannelStream.setId(liveChannelStream.getId());
                tChannelStream.setFatherId(liveChannelStream.getFatherId());
                tChannelStream.setStreamName(liveChannelStream.getStreamName());
                tChannelStream.setSliceIndex(Integer.parseInt(sliceIndex));
                return tChannelStream;
            }else {
                return null;
            }

        } catch (Exception e) {
            logger.info("[notifyChange][error][exception={}]", e);
            return null;

        }
    }
}
